home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1997 / MacHack 1997.toast / Hacks / Hacks ’94 / [√] Distribution Restricted! / Christian Ruse / Fourier Paper + Apps / nih-image154_source.sea / V1.54 Source / Projection.p < prev    next >
Text File  |  1993-10-15  |  47KB  |  1,019 lines

  1. unit Projection;
  2. {************************************************************************}
  3. {*     Projection.p                                                                                                                                          *}
  4. {*     by Michael Castle (Pascal) and Janice Keller (assembly code)                                                          *}
  5. {*     University of Michigan Mental Health Research Institute (MHRI)                                                     *}
  6. {*     e-mail address: mike_castle@um.cc.umich.edu                                                                                   *}
  7. {* ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * }
  8.  
  9. interface
  10.  
  11.     uses
  12.         QuickDraw, PrintTraps, Palettes, Globals, Utilities, File2, File1, Graphics, Camera, Filters, Stacks;
  13.  
  14.  
  15.     procedure DoProjection;
  16.     function ShowProjectDialogBox: boolean;
  17.     procedure Project;
  18.  
  19.  
  20. implementation
  21.  
  22.     const
  23.         bigpowerof2 = 8192;                               {used for integer trigonometric arithmetic}
  24.  
  25.     type
  26.         MHRIRealArray = array[1..MaxPics] of real;
  27.         RealPoint = record
  28.                 x: real;
  29.                 y: real;
  30.             end;     {record}
  31.         IntPtr = ^integer;
  32.         LongPtr = ^LongInt;
  33.  
  34.     var
  35.         SliceInterval: real;                                 {distance, in pixels, between original slices}
  36.         BoundRect: rect;                                      {boundary rectangle for a rectangular selection}
  37.         cancelled: boolean;
  38.         lower, upper: integer;
  39.         ProjSize: LongInt;
  40.  
  41.  
  42.  
  43. {******************************************************************************}
  44. {*     This procedure frees memory allocated for buffers used in projection calculations.                                       *}
  45. {******************************************************************************}
  46.     procedure DisposeProjectionPtrs (projptr, opaptr, brightcueptr: ptr; zbufptr, countbufptr, cuezbufptr: IntPtr; sumbufptr: LongPtr);
  47.     begin
  48.         if zbufptr <> nil then
  49.             DisposPtr(Ptr(zbufptr));
  50.         if opaptr <> nil then
  51.             DisposPtr(opaptr);
  52.         if sumbufptr <> nil then
  53.             DisposPtr(Ptr(sumbufptr));
  54.         if countbufptr <> nil then
  55.             DisposPtr(Ptr(countbufptr));
  56.         if cuezbufptr <> nil then
  57.             DisposPtr(Ptr(cuezbufptr));
  58.         if brightcueptr <> nil then
  59.             DisposPtr(brightcueptr);
  60.         if projptr <> nil then
  61.             DisposPtr(projptr);
  62.     end;
  63.  
  64.  
  65. {******************************************************************************}
  66. {*     This procedure projects each pixel of a volume (stack of slices) onto a plane as the volume rotates about    *}
  67. {*  the x-axis.  Integer arithmetic, precomputation of values, and iterative addition rather than multiplication  *}
  68. {*  inside a loop are used extensively to make the code run efficiently.  Projection parameters stored in global   *}
  69. {*  variables determine how the projection will be performed.  This procedure returns various buffers which   *}
  70. {*  are actually used by DoProject to find the final projected image for the volume of slices at the current angle.*}
  71. {******************************************************************************}
  72.     procedure DoOneProjectionX (nSlices, ycenter, zcenter, projwidth, projheight: integer; costheta, sintheta: longint; projptr, opaptr, brightcueptr: ptr; zbufptr, cuezbufptr, countbufptr: IntPtr; sumbufptr: LongPtr; str: string);
  73.         var
  74.             i, j, k,                                                 {loop indices}
  75.             thispixel: integer;                              {the current pixel to be projected}
  76.             offset, offsetinit: longint;                   {precomputed offsets into an image buffer}
  77.             projaddr,                                            {buffer address for final projected image}
  78.             opaaddr,                                              {buffer address for opacity surface projection component}
  79.             brightcueaddr,                                   {buffer address for brightest-point projection with interior depth cues}
  80.             zbufaddr,                                            {z-buffer address for surface projections (nearest-point/opacity)}
  81.             cuezbufaddr,                                       {z-buffer address for brightest-point projection with interior depth cues}
  82.             countbufaddr,                                     {buffer addr for counting pixels in mean-value projection}
  83.             sumbufaddr: longint;                         {buffer addr for summing pixels in mean-value projection}
  84.             z,                                                        {z-coordinate of points in current slice before rotation}
  85.             ynew, znew,                                       {y- and z-coordinates of current point after rotation}
  86.             zmax, zmin,                                       {z-coordinates of first and last slices before rotation}
  87.             zmaxminuszmintimes100: longint;  {precomputed values to save time in loops}
  88.             c100minusDepthCueInt, c100minusDepthCueSurf: integer;
  89.             DepthCueIntlessthan100, DepthCueSurflessthan100: boolean;
  90.             OpacityOrNearestPt, OpacityAndNotNearestPt: boolean;
  91.             MeanVal, BrightestPt: boolean;
  92.             ysintheta, ycostheta,                          {values used in rotational calculations before projection}
  93.             zsintheta, zcostheta, ysinthetainit, ycosthetainit: longint;
  94.             p,                                                        {pointer to final projected image buffer}
  95.             op,                                                      {pointer to opacity surface projection buffer}
  96.             bp: ptr;                                              {pointer to brightest-point projection buffer with interior depth cues}
  97.             zp,                                                      {pointer to surface projection (nearest-point/opacity) z-buffer}
  98.             qp,                                                      {pointer to z-buffer for brightest-point projection with interior depth cues}
  99.             cp: IntPtr;                                          {pointer to buffer for counting pixels for mean-value projection}
  100.             sp: LongPtr;                                       {pointer to mean-value summing buffer}
  101.             width: integer;
  102.             theLine: LineType;
  103.     begin
  104.         with BoundRect do begin                    {precompute values to avoid computations in loop}
  105.                 width := right - left;
  106.                 zmax := zcenter + projheight div 2; {find z-coordinates of first and last slices}
  107.                 zmin := zcenter - projheight div 2;
  108.                 zmaxminuszmintimes100 := 100 * (zmax - zmin);
  109.                 c100minusDepthCueInt := 100 - DepthCueInt;
  110.                 c100minusDepthCueSurf := 100 - DepthCueSurf;
  111.                 DepthCueIntlessthan100 := DepthCueInt < 100;
  112.                 DepthCueSurflessthan100 := DepthCueSurf < 100;
  113.                 OpacityOrNearestPt := (ProjectionMethod = NearestPoint) or (Opacity > 0);
  114.                 OpacityAndNotNearestPt := (Opacity > 0) and (ProjectionMethod <> NearestPoint);
  115.                 MeanVal := ProjectionMethod = MeanValue;
  116.                 BrightestPt := ProjectionMethod = BrightestPoint;
  117.                 projaddr := ord4(projptr);
  118.                 opaaddr := ord4(opaptr);
  119.                 brightcueaddr := ord4(brightcueptr);
  120.                 zbufaddr := ord4(zbufptr);
  121.                 cuezbufaddr := ord4(cuezbufptr);
  122.                 countbufaddr := ord4(countbufptr);
  123.                 sumbufaddr := ord4(sumbufptr);
  124.                 ycosthetainit := (top - ycenter - 1) * costheta;
  125.                 ysinthetainit := (top - ycenter - 1) * sintheta;
  126.                 offsetinit := ((projheight - bottom + top) div 2) * projwidth + (projwidth - right + left) div 2 - 1;
  127.                 for k := 1 to nSlices do begin
  128.                         SelectSlice(k);
  129.                         z := round((k - 1) * SliceInterval) - zcenter;
  130.                         zcostheta := z * costheta;
  131.                         zsintheta := z * sintheta;
  132.                         ycostheta := ycosthetainit;
  133.                         ysintheta := ysinthetainit;
  134.                         for j := top to bottom - 1 do begin               {read each row in the current slice}
  135.                                 ycostheta := ycostheta + costheta;               {rotate about x-axis and find new y,z}
  136.                                 ysintheta := ysintheta + sintheta;               {x-coordinates will not change}
  137.                                 ynew := (ycostheta - zsintheta) div bigpowerof2 + ycenter - top;
  138.                                 znew := (ysintheta + zcostheta) div bigpowerof2 + zcenter;
  139.                                 offset := offsetinit + ynew * projwidth;
  140.                                 GetLine(left, j, width, theLine);
  141.                                 for i := 0 to width - 1 do begin             {read each pixel in current row and project it}
  142.                                         thispixel := theLine[i];
  143.                                         offset := offset + 1;
  144.                                         if (offset >= ProjSize) or (offset < 0) then
  145.                                             offset := 0;
  146.                                         if (thispixel <= Upper) and (thispixel >= Lower) then begin
  147.                                                 if OpacityOrNearestPt then begin
  148.                                                         zp := IntPtr(zbufaddr + offset + offset);
  149.                                                         if (znew < zp^) then begin
  150.                                                                 zp^ := znew;
  151.                                                                 if OpacityAndNotNearestPt then begin
  152.                                                                         op := ptr(opaaddr + offset);
  153.                                                                         if (DepthCueSurflessthan100) then
  154.                                                                             op^ := 255 - (DepthCueSurf * (255 - thispixel) div 100 + (c100minusDepthCueSurf) * (255 - thispixel) * (zmax - znew) div zmaxminuszmintimes100)
  155.                                                                         else
  156.                                                                             op^ := thispixel;
  157.                                                                     end
  158.                                                                 else begin
  159.                                                                         p := ptr(projaddr + offset);
  160.                                                                         if DepthCueSurflessthan100 then
  161.                                                                             p^ := 255 - (DepthCueSurf * (255 - thispixel) div 100 + (c100minusDepthCueSurf) * (255 - thispixel) * (zmax - znew) div zmaxminuszmintimes100)
  162.                                                                         else
  163.                                                                             p^ := thispixel;
  164.                                                                     end;
  165.                                                             end;
  166.                                                     end;     {NearestPoint case}
  167.                                                 if MeanVal then begin
  168.                                                         sp := LongPtr(sumbufaddr + offset + offset + offset + offset);
  169.                                                         sp^ := sp^ + thispixel;
  170.                                                         cp := IntPtr(countbufaddr + offset + offset);
  171.                                                         cp^ := cp^ + 1;
  172.                                                     end     {MeanValue case}
  173.                                                 else if BrightestPt then begin
  174.                                                         if (DepthCueIntlessthan100) then begin
  175.                                                                 p := ptr(projaddr + offset);
  176.                                                                 bp := ptr(brightcueaddr + offset);
  177.                                                                 qp := IntPtr(cuezbufaddr + offset + offset);
  178.                                                                 if (thispixel < BAND(bp^, 255)) or ((thispixel = BAND(bp^, 255)) and (znew < qp^)) then begin
  179.                                                                         bp^ := thispixel;                     {use z-buffer to ensure that if depth-cueing is on,  }
  180.                                                                         qp^ := znew;                            {the closer of two equally-bright points is displayed}
  181.                                                                         p^ := 255 - (DepthCueInt * (255 - thispixel) div 100 + (c100minusDepthCueInt) * (255 - thispixel) * (zmax - znew) div zmaxminuszmintimes100);
  182.                                                                     end;     {then}
  183.                                                             end
  184.                                                         else begin
  185.                                                                 p := ptr(projaddr + offset);
  186.                                                                 if (thispixel < BAND(p^, 255)) then
  187.                                                                     p^ := thispixel;
  188.                                                             end;     {else}
  189.                                                     end;     {BrightestPoint case}
  190.                                             end;
  191.                                     end;     {for j}
  192.                             end;     {for i}
  193.                         UpdateMeter(10 + (k * 90) div nSlices, str);
  194.                         if CommandPeriod then begin
  195.                                 cancelled := true;
  196.                                 beep;
  197.                                 leave;
  198.                             end;
  199.                     end;     {for k}
  200.             end;     {with}
  201.     end;     {procedure DoOneProjectionX}
  202.  
  203.  
  204.  
  205. {******************************************************************************}
  206. {*     This procedure projects each pixel of a volume (stack of slices) onto a plane as the volume rotates about    *}
  207. {*  the y-axis.  Integer arithmetic, precomputation of values, and iterative addition rather than multiplication  *}
  208. {*  inside a loop are used extensively to make the code run efficiently.  Projection parameters stored in global   *}
  209. {*  variables determine how the projection will be performed.  This procedure returns various buffers which   *}
  210. {*  are actually used by DoProject to find the final projected image for the volume of slices at the current angle.*}
  211. {******************************************************************************}
  212.     procedure DoOneProjectionY (nSlices, xcenter, zcenter, projwidth, projheight: integer; costheta, sintheta: longint; projptr, opaptr, brightcueptr: ptr; zbufptr, cuezbufptr, countbufptr: IntPtr; sumbufptr: LongPtr; str: string);
  213.         var
  214.             i, j, k, thispixel: integer;
  215.             offset, offsetinit: longint;
  216.             projaddr, opaaddr, brightcueaddr, zbufaddr, cuezbufaddr, countbufaddr, sumbufaddr: longint;
  217.             z, xnew, znew, zmax, zmin, zmaxminuszmintimes100: longint;
  218.             c100minusDepthCueInt, c100minusDepthCueSurf: integer;
  219.             DepthCueIntlessthan100, DepthCueSurflessthan100: boolean;
  220.             OpacityOrNearestPt, OpacityAndNotNearestPt: boolean;
  221.             MeanVal, BrightestPt: boolean;
  222.             xsintheta, xcostheta, zsintheta, zcostheta, xsinthetainit, xcosthetainit: longint;
  223.             p, op, bp: ptr;
  224.             zp, qp, cp: IntPtr;
  225.             sp: LongPtr;
  226.             width: integer;
  227.             aLine: LineType;
  228.     begin
  229.         with BoundRect do begin
  230.                 width := right - left;
  231.                 zmax := zcenter + projwidth div 2;
  232.                 zmin := zcenter - projwidth div 2;
  233.                 zmaxminuszmintimes100 := 100 * (zmax - zmin);
  234.                 c100minusDepthCueInt := 100 - DepthCueInt;
  235.                 c100minusDepthCueSurf := 100 - DepthCueSurf;
  236.                 DepthCueIntlessthan100 := DepthCueInt < 100;
  237.                 DepthCueSurflessthan100 := DepthCueSurf < 100;
  238.                 OpacityOrNearestPt := (ProjectionMethod = NearestPoint) or (Opacity > 0);
  239.                 OpacityAndNotNearestPt := (Opacity > 0) and (ProjectionMethod <> NearestPoint);
  240.                 MeanVal := ProjectionMethod = MeanValue;
  241.                 BrightestPt := ProjectionMethod = BrightestPoint;
  242.                 projaddr := ord4(projptr);
  243.                 opaaddr := ord4(opaptr);
  244.                 brightcueaddr := ord4(brightcueptr);
  245.                 zbufaddr := ord4(zbufptr);
  246.                 cuezbufaddr := ord4(cuezbufptr);
  247.                 countbufaddr := ord4(countbufptr);
  248.                 sumbufaddr := ord4(sumbufptr);
  249.                 xcosthetainit := (left - xcenter - 1) * costheta;
  250.                 xsinthetainit := (left - xcenter - 1) * sintheta;
  251.                 for k := 1 to nSlices do begin
  252.                         SelectSlice(k);
  253.                         z := round((k - 1) * SliceInterval) - zcenter;
  254.                         zcostheta := z * costheta;
  255.                         zsintheta := z * sintheta;
  256.                         offsetinit := ((projheight - bottom + top) div 2) * projwidth + (projwidth - right + left) div 2 - projwidth;
  257.                         for j := top to bottom - 1 do begin
  258.                                 xcostheta := xcosthetainit;
  259.                                 xsintheta := xsinthetainit;
  260.                                 offsetinit := offsetinit + projwidth;
  261.                                 GetLine(left, j, width, aLine);
  262.                                 for i := 0 to width - 1 do begin
  263.                                         thispixel := aLine[i];
  264.                                         xcostheta := xcostheta + costheta;
  265.                                         xsintheta := xsintheta + sintheta;
  266.                                         if (thispixel <= Upper) and (thispixel >= Lower) then begin
  267.                                                 xnew := (xcostheta + zsintheta) div bigpowerof2 + xcenter - left;
  268.                                                 znew := (zcostheta - xsintheta) div bigpowerof2 + zcenter;
  269.                                                 offset := offsetinit + xnew;
  270.                                                 if (offset >= ProjSize) or (offset < 0) then
  271.                                                     offset := 0;
  272.                                                 if OpacityOrNearestPt then begin
  273.                                                         zp := IntPtr(zbufaddr + offset + offset);
  274.                                                         if (znew < zp^) then begin
  275.                                                                 zp^ := znew;
  276.                                                                 if OpacityAndNotNearestPt then begin
  277.                                                                         op := ptr(opaaddr + offset);
  278.                                                                         if (DepthCueSurflessthan100) then
  279.                                                                             op^ := 255 - (DepthCueSurf * (255 - thispixel) div 100 + (c100minusDepthCueSurf) * (255 - thispixel) * (zmax - znew) div zmaxminuszmintimes100)
  280.                                                                         else
  281.                                                                             op^ := thispixel;
  282.                                                                     end
  283.                                                                 else begin
  284.                                                                         p := ptr(projaddr + offset);
  285.                                                                         if DepthCueSurflessthan100 then
  286.                                                                             p^ := 255 - (DepthCueSurf * (255 - thispixel) div 100 + (c100minusDepthCueSurf) * (255 - thispixel) * (zmax - znew) div zmaxminuszmintimes100)
  287.                                                                         else
  288.                                                                             p^ := thispixel;
  289.                                                                     end;
  290.                                                             end;
  291.                                                     end;     {NearestPoint case}
  292.                                                 if MeanVal then begin
  293.                                                         sp := LongPtr(sumbufaddr + offset + offset + offset + offset);
  294.                                                         sp^ := sp^ + thispixel;
  295.                                                         cp := IntPtr(countbufaddr + offset + offset);
  296.                                                         cp^ := cp^ + 1;
  297.                                                     end     {MeanValue case}
  298.                                                 else if BrightestPt then begin
  299.                                                         if (DepthCueIntlessthan100) then begin
  300.                                                                 p := ptr(projaddr + offset);
  301.                                                                 bp := ptr(brightcueaddr + offset);
  302.                                                                 qp := IntPtr(cuezbufaddr + offset + offset);
  303.                                                                 if (thispixel < BAND(bp^, 255)) or ((thispixel = BAND(bp^, 255)) and (znew < qp^)) then begin
  304.                                                                         bp^ := thispixel;
  305.                                                                         qp^ := znew;
  306.                                                                         p^ := 255 - (DepthCueInt * (255 - thispixel) div 100 + (c100minusDepthCueInt) * (255 - thispixel) * (zmax - znew) div zmaxminuszmintimes100);
  307.                                                                     end;     {then}
  308.                                                             end
  309.                                                         else begin
  310.                                                                 p := ptr(projaddr + offset);
  311.                                                                 if (thispixel < BAND(p^, 255)) then
  312.                                                                     p^ := thispixel;
  313.                                                             end;     {else}
  314.                                                     end;     {BrightestPoint case}
  315.                                             end;
  316.                                     end;     {for j}
  317.                             end;     {for i}
  318.                         UpdateMeter(10 + (k * 90) div nSlices, str);
  319.                         if CommandPeriod then begin
  320.                                 cancelled := true;
  321.                                 beep;
  322.                                 leave;
  323.                             end;
  324.                     end;     {for k}
  325.             end;     {with}
  326.     end;     {procedure DoOneProjectionY}
  327.  
  328.  
  329.  
  330. {******************************************************************************}
  331. {*     This procedure projects each pixel of a volume (stack of slices) onto a plane as the volume rotates about    *}
  332. {*  the z-axis.  Integer arithmetic, precomputation of values, and iterative addition rather than multiplication  *}
  333. {*  inside a loop are used extensively to make the code run efficiently.  Projection parameters stored in global   *}
  334. {*  variables determine how the projection will be performed.  This procedure returns various buffers which   *}
  335. {*  are actually used by DoProject to find the final projected image for the volume of slices at the current angle.*}
  336. {******************************************************************************}
  337.     procedure DoOneProjectionZ (nSlices, xcenter, ycenter, zcenter, projwidth, projheight: integer; costheta, sintheta: longint; projptr, opaptr, brightcueptr: ptr; zbufptr, cuezbufptr, countbufptr: IntPtr; sumbufptr: LongPtr; str: string);
  338.         var
  339.             i, j, k, thispixel: integer;
  340.             offset, offsetinit: longint;
  341.             projaddr, opaaddr, brightcueaddr, zbufaddr, cuezbufaddr, countbufaddr, sumbufaddr: longint;
  342.             z, xnew, ynew, zmax, zmin, zmaxminuszmintimes100: longint;
  343.             c100minusDepthCueInt, c100minusDepthCueSurf: integer;
  344.             DepthCueIntlessthan100, DepthCueSurflessthan100: boolean;
  345.             OpacityOrNearestPt, OpacityAndNotNearestPt: boolean;
  346.             MeanVal, BrightestPt: boolean;
  347.             xsintheta, xcostheta, ysintheta, ycostheta: longint;
  348.             xsinthetainit, xcosthetainit, ysinthetainit, ycosthetainit: longint;
  349.             p, op, bp: ptr;
  350.             zp, qp, cp: IntPtr;
  351.             sp: LongPtr;
  352.             width: integer;
  353.             theLine: LineType;
  354.     begin
  355.         with BoundRect do begin
  356.                 width := right - left;
  357.                 zmax := zcenter + projwidth div 2;
  358.                 zmin := zcenter - projwidth div 2;
  359.                 zmaxminuszmintimes100 := 100 * (zmax - zmin);
  360.                 c100minusDepthCueInt := 100 - DepthCueInt;
  361.                 c100minusDepthCueSurf := 100 - DepthCueSurf;
  362.                 DepthCueIntlessthan100 := DepthCueInt < 100;
  363.                 DepthCueSurflessthan100 := DepthCueSurf < 100;
  364.                 OpacityOrNearestPt := (ProjectionMethod = NearestPoint) or (Opacity > 0);
  365.                 OpacityAndNotNearestPt := (Opacity > 0) and (ProjectionMethod <> NearestPoint);
  366.                 MeanVal := ProjectionMethod = MeanValue;
  367.                 BrightestPt := ProjectionMethod = BrightestPoint;
  368.                 projaddr := ord4(projptr);
  369.                 opaaddr := ord4(opaptr);
  370.                 brightcueaddr := ord4(brightcueptr);
  371.                 zbufaddr := ord4(zbufptr);
  372.                 cuezbufaddr := ord4(cuezbufptr);
  373.                 countbufaddr := ord4(countbufptr);
  374.                 sumbufaddr := ord4(sumbufptr);
  375.                 xcosthetainit := (left - xcenter - 1) * costheta;
  376.                 xsinthetainit := (left - xcenter - 1) * sintheta;
  377.                 ycosthetainit := (top - ycenter - 1) * costheta;
  378.                 ysinthetainit := (top - ycenter - 1) * sintheta;
  379.                 offsetinit := ((projheight - bottom + top) div 2) * projwidth + (projwidth - right + left) div 2 + left - 1;
  380.                 for k := 1 to nSlices do begin
  381.                         SelectSlice(k);
  382.                         z := round((k - 1) * SliceInterval) - zcenter;
  383.                         ycostheta := ycosthetainit;
  384.                         ysintheta := ysinthetainit;
  385.                         for j := top to bottom - 1 do begin
  386.                                 ycostheta := ycostheta + costheta;
  387.                                 ysintheta := ysintheta + sintheta;
  388.                                 xcostheta := xcosthetainit;
  389.                                 xsintheta := xsinthetainit;
  390.                                 GetLine(left, j, width, theLine);
  391.                                 for i := 0 to width - 1 do begin
  392.                                         thisPixel := theLine[i];
  393.                                         xcostheta := xcostheta + costheta;
  394.                                         xsintheta := xsintheta + sintheta;
  395.                                         if (thispixel <= Upper) and (thispixel >= Lower) then begin
  396.                                                 xnew := (xcostheta - ysintheta) div bigpowerof2 + xcenter - left;
  397.                                                 ynew := (xsintheta + ycostheta) div bigpowerof2 + ycenter - top;
  398.                                                 offset := offsetinit + ynew * projwidth + xnew;
  399.                                                 if (offset >= ProjSize) or (offset < 0) then
  400.                                                     offset := 0;
  401.                                                 if OpacityOrNearestPt then begin
  402.                                                         zp := IntPtr(zbufaddr + offset + offset);
  403.                                                         if (z < zp^) then begin
  404.                                                                 zp^ := z;
  405.                                                                 if OpacityAndNotNearestPt then begin
  406.                                                                         op := ptr(opaaddr + offset);
  407.                                                                         if (DepthCueSurflessthan100) then
  408.                                                                             op^ := 255 - (DepthCueSurf * (255 - thispixel) div 100 + (c100minusDepthCueSurf) * (255 - thispixel) * (zmax - z) div zmaxminuszmintimes100)
  409.                                                                         else
  410.                                                                             op^ := thispixel;
  411.                                                                     end
  412.                                                                 else begin
  413.                                                                         p := ptr(projaddr + offset);
  414.                                                                         if DepthCueSurflessthan100 then
  415.                                                                             p^ := 255 - (DepthCueSurf * (255 - thispixel) div 100 + (c100minusDepthCueSurf) * (255 - thispixel) * (zmax - z) div zmaxminuszmintimes100)
  416.                                                                         else
  417.                                                                             p^ := thispixel;
  418.                                                                     end;
  419.                                                             end;
  420.                                                     end;     {NearestPoint case}
  421.                                                 if MeanVal then begin
  422.                                                         sp := LongPtr(sumbufaddr + offset + offset + offset + offset);
  423.                                                         sp^ := sp^ + thispixel;
  424.                                                         cp := IntPtr(countbufaddr + offset + offset);
  425.                                                         cp^ := cp^ + 1;
  426.                                                     end     {MeanValue case}
  427.                                                 else if BrightestPt then begin
  428.                                                         if (DepthCueIntlessthan100) then begin
  429.                                                                 p := ptr(projaddr + offset);
  430.                                                                 bp := ptr(brightcueaddr + offset);
  431.                                                                 qp := IntPtr(cuezbufaddr + offset + offset);
  432.                                                                 if (thispixel < BAND(bp^, 255)) or ((thispixel = BAND(bp^, 255)) and (z < qp^)) then begin
  433.                                                                         bp^ := thispixel;
  434.                                                                         qp^ := z;
  435.                                                                         p^ := 255 - (DepthCueInt * (255 - thispixel) div 100 + (c100minusDepthCueInt) * (255 - thispixel) * (zmax - z) div zmaxminuszmintimes100);
  436.                                                                     end;     {then}
  437.                                                             end
  438.                                                         else begin
  439.                                                                 p := ptr(projaddr + offset);
  440.                                                                 if (thispixel < BAND(p^, 255)) then
  441.                                                                     p^ := thispixel;
  442.                                                             end;     {else}
  443.                                                     end;     {BrightestPoint case}
  444.                                             end;
  445.                                     end;     {for j}
  446.                             end;     {for i}
  447.                         UpdateMeter(10 + (k * 90) div nSlices, str);
  448.                         if CommandPeriod then begin
  449.                                 cancelled := true;
  450.                                 beep;
  451.                                 leave;
  452.                             end;
  453.                     end;     {for k}
  454.             end;     {with}
  455.     end;     {procedure DoOneProjectionZ}
  456.  
  457.  
  458.  
  459. {******************************************************************************}
  460. {*     This code initializes buffers by filling them with uniform values.  The buffers may be filled with               *}
  461. {*  one-byte, two-byte, or four-byte values (maybe others, too!).  Since multiple, huge buffers are                  *}
  462. {*  allocated for projection calculations, we have decided to write this procedure in assembly language.               *}
  463. {*  Assembly code written by Janice Keller.                                                                                                              *}
  464. {******************************************************************************}
  465.     procedure InitializeBuffer (p: ptr; size: longint; value, step: integer);
  466.     inline
  467.         $4E56, $0000,                    {link  A6,#0}
  468.         $48E7, $F880,          {movem.l  a0/d0-d4, -(sp)}
  469.         $342E, $0004,         {move.w   4(a6),d2               step}
  470.         $7000,                     {clr.l  d0                               set high word}
  471.         $302E, $0006,         {move.w   6(a6),d0               value to set}
  472.         $222E, $0008,         {move.l   8(a6),d1               projsize}
  473.         $206E, $000C,         {movea.l  12(a6),a0             start address}
  474.         $7600,                     {Test1 clr.l   d3                   set remainder to 0}
  475.         $0881, $0000,        {bclr.l       #0,d1                  test for 1 and zero}
  476.         $6702,                    {beq.b       Test2                    if 1, save it, else continue}
  477.         $7601,                     {moveq.l     #1,d3                remainder is 1}
  478.         $0881, $0001,        {Test2  bclr.l  #1,d1             test for 2 or 3}
  479.         $6702,                    {beq.b  SetValues                   if found 1, set remainder}
  480.         $5403,                    {addq.b     #2,d3                   remainder + 2}
  481.         $7801,                    {SetValues moveq.l    #1,d4  decrement projsize by 1 for step 4}
  482.         $0C02, $0004,        {cmp.b   #4,d2     if step is 4...}
  483.         $6716,                    {beq.b     SetInit                    start initting}
  484.         $7802,                    {moveq.l  #2,d4                   decr projsize by 2 for step 2}
  485.         $0C02, $0002,        {cmp.b     #2,d2                   if step is 2...}
  486.         $6708,                   {beq.b   DoubleIt                    just have to double}
  487.         $7804,                    {moveq.l   #4,d4                  decre projsize by 4 for step 1}
  488.         $1400,                    {move.b   d0,d2                    else we have a 1-er}
  489.         $E148,                    {lsl.w   #8,d0                       lo to hi}
  490.         $1002,                    {move.b  d2,d0                     reset lo}
  491.         $3400,                   {DoubleIt  move.w d0,d2        save the lo word}
  492.         $4840,                   {swap  d0                              move lo to hi}
  493.         $3002,                   {move.w  d2,d0                     reset lo}
  494.         $20C0,                   {SetInit   move.l   d0,(a0)+    set this address}
  495.         $9284,                   {sub.l  d4,d1                         decr projsize}
  496.         $0C81, $0000, $0000,  {cmp.l   #0,d1               are we done yet}
  497.         $6EF4,                   {bgt.b  SetInit                                                no}
  498.         $0C03, $0000,      {Remainder  cmp.b  #0,d3     is there anything left}
  499.         $672C,                  {beq.b   Exit                           no, all done}
  500.         $5383,                  {subq.l  #1,d3                              0-2, not 1-3}
  501.         $302E, $0006,      {move.w  6(a6),d0                 get the value}
  502.         $342E, $0004,      {move.w 4(a6),d2                  get the step}
  503.         $0C02, $0004,        {cmp.b  #4,d2                        is this a step 4}
  504.         $6608,                     {bne.b   Teststep2                  no}
  505.         $20C0,                   {Loop4   move.l  d0,(a0)+      yes, set long}
  506.         $51CB, $FFFC,       {dbra   d3,Loop4                    next one}
  507.         $6014,                  {bra.b  Exit}
  508.         $0C02, $0002,      {TestStep2   cmp.b  #2,d2     is this a step 2}
  509.         $6608,                 {bne.b   Loop1                       no, must be a 1}
  510.         $30C0,                 {Loop2  move.w  d0,(a0)+     yes, set word}
  511.         $51CB, $FFFC,       {dbra   d3,Loop2                    next one}
  512.         $6006,                 {bra.b  Exit}
  513.         $10C0,                 {Loop1  move.b   d0,(a0)+      set bytes}
  514.         $51CB, $FFFC,      {dbra  d3,Loop1                     next one}
  515.         $4CDF, $011F,       {Exit  movem.l    (sp)+,a0/d0-d4}
  516.         $4E5E,                   {unlk    a6}
  517.         $DEFC, $000C;      {add.w   #12,sp}
  518. {this Pascal code works except for the fact that the pointer must change type with step}
  519. {so if you want to use the Pascal, you'll need a case statement for each allowable size}
  520. {$IFC false}
  521.     var
  522.         offset: longint;
  523. begin
  524.     for offset := 0 to size - 1 do begin
  525.             p^ := value;
  526.             p := Ptr(ord4(p) + step);
  527.         end;     {for}
  528. end;     {procedure InitializeBuffer}
  529. {$ENDC}
  530.  
  531.  
  532. {******************************************************************************}
  533. {*     This procedure creates a sequence of projections of a rotating volume (stack of slices) onto a plane using   *}
  534. {*  nearest-point (surface), brightest-point, or mean-value projection or a weighted combination of nearest- *}
  535. {*  point projection with either of the other two methods (partial opacity).  The user may choose to rotate the   *}
  536. {*  volume about any of the three orthogonal axes (x,y, or z), make portions of the volume transparent, or add  *}
  537. {*  a greater degree of visual realism by employing depth cues.                                                                               *}
  538. {******************************************************************************}
  539. procedure DoProjection;
  540.     var
  541.         tport: Grafptr;
  542.         nSlices: integer;                                      {number of slices in volume}
  543.         projwidth, projheight: integer;              {dimensions of projection image}
  544.         xcenter, ycenter, zcenter: integer;         {coordinates of center of volume of rotation}
  545.         theta: integer;                                          {current angle of rotation in degrees}
  546.         thetarad: real;                                          {current angle of rotation in radians}
  547.         sintheta, costheta: longint;                      {sine and cosine of current angle}
  548.         xsinthetainit, xcosthetainit: longint;      {precomputed products to avoid mult in loops}
  549.         offset, MemoryRequired: longint;
  550.         p, op, bp, projptr, opaptr, brightcueptr: ptr;
  551.         zp, zbufptr, qp, cuezbufptr, countbufptr, cp: IntPtr;
  552.         sp, sumbufptr: LongPtr;
  553.         curval, prevval, nextval, aboveval, belowval: integer;
  554.         ignore: integer;                                        {irrelevant return value from a function}
  555.         ticksinit, tickstogo, TicksForOneProjection: longint;
  556.         str, TimeStr, seconds: string;
  557.         SaveProjectionsTemp, AutoSelectAll, AllocatingBuffers: boolean;
  558.         n, nProjections, angle: integer;
  559.         SourceInfo, DestInfo: InfoPtr;
  560.  
  561.     procedure Abort;
  562.     begin
  563.         DisposeProjectionPtrs(projptr, opaptr, brightcueptr, zbufptr, countbufptr, cuezbufptr, sumbufptr);
  564.         if AllocatingBuffers and (MaxBlock > 20000) then
  565.             PutMessage('Insufficient Memory.');
  566.         macro := false;
  567.         exit(DoProjection);
  568.     end;
  569.  
  570. begin
  571.     ShowWatch;
  572.     AutoSelectAll := not Info^.RoiShowing;
  573.     if AutoSelectAll then
  574.         SelectAll(false);
  575.     if NotInBounds then
  576.         exit(DoProjection);
  577.     cancelled := false;
  578.     SourceInfo := Info;
  579.     GetPort(tPort);
  580.     with Info^ do begin
  581.             SetPort(GrafPtr(osPort));
  582.             BoundRect := Roirect;
  583.         end;
  584.     if (AngleInc = 0) and (TotalAngle <> 0) then
  585.         AngleInc := 5;
  586.     angle := 0;
  587.     nProjections := 0;
  588.     if AngleInc = 0 then
  589.         nProjections := 1
  590.     else
  591.         while angle <= TotalAngle do begin
  592.                 nProjections := nProjections + 1;
  593.                 angle := angle + AngleInc;
  594.             end;
  595.     if angle > 360 then
  596.         nProjections := nProjections - 1;
  597.     if nProjections <= 0 then
  598.         nProjections := 1;
  599.     nSlices := Info^.StackInfo^.nSlices;         {get number of slices in volume}
  600.     with BoundRect do begin
  601.             xcenter := (left + right) div 2;          {find center of volume of rotation}
  602.             ycenter := (top + bottom) div 2;
  603.             zcenter := round(nSlices * SliceInterval / 2.0);
  604.             if MinProjSize and (AxisOfRotation <> ZAxis) then begin
  605.                     case AxisOfRotation of                    {find dimensions of projection image}
  606.                         XAxis:  begin
  607.                                 projheight := round(sqrt(sqr(nSlices * SliceInterval) + longint(bottom - top) * (bottom - top)));
  608.                                 projwidth := right - left;
  609.                             end;     {XAxis}
  610.                         YAxis:  begin
  611.                                 projwidth := round(sqrt(sqr(nSlices * SliceInterval) + longint(right - left) * (right - left)));
  612.                                 projheight := bottom - top;
  613.                             end;     {YAxis}
  614.                     end;     {case}
  615.                 end     {then}
  616.             else begin
  617.                     projwidth := round(sqrt(sqr(nSlices * SliceInterval) + longint(right - left) * (right - left)));
  618.                     projheight := round(sqrt(sqr(nSlices * SliceInterval) + longint(bottom - top) * (bottom - top)));
  619.                 end;     {else make all windows the same size regardless of rotation axis}
  620.         end;     {with BoundRect}
  621.     if odd(projwidth) then
  622.         projwidth := projwidth + 1;
  623.     projptr := nil;
  624.     zbufptr := nil;
  625.     opaptr := nil;
  626.     brightcueptr := nil;
  627.     cuezbufptr := nil;
  628.     sumbufptr := nil;
  629.     countbufptr := nil;
  630.     AllocatingBuffers := true;
  631.     projsize := longint(projwidth) * longint(projheight);
  632.     projptr := NewPtr(projsize);
  633.     if projptr = nil then
  634.         Abort;
  635.     if (ProjectionMethod = NearestPoint) or (Opacity > 0) then begin    {get other required buffers}
  636.             zbufptr := IntPtr(NewPtr(projsize * 2));
  637.             if zbufptr = nil then
  638.                 Abort;
  639.         end;
  640.     if (Opacity > 0) and (ProjectionMethod <> NearestPoint) then begin
  641.             opaptr := NewPtr(projsize);
  642.             if opaptr = nil then
  643.                 Abort;
  644.         end;
  645.     if (ProjectionMethod = BrightestPoint) and (DepthCueInt < 100) then begin
  646.             brightcueptr := NewPtr(projsize);
  647.             cuezbufptr := IntPtr(NewPtr(projsize * 2));
  648.             if (brightcueptr = nil) or (cuezbufptr = nil) then
  649.                 abort;
  650.         end;
  651.     if (ProjectionMethod = MeanValue) then begin
  652.             sumbufptr := LongPtr(NewPtr(projsize * 4));
  653.             countbufptr := IntPtr(NewPtr(projsize * 2));
  654.             if (sumbufptr = nil) or (countbufptr = nil) then
  655.                 abort;
  656.         end;
  657.     AllocatingBuffers := false;
  658.     SaveProjectionsTemp := FALSE;              {check whether we have enough memory to open}
  659.     MemoryRequired := nProjections * projsize + SizeOf(PicInfo) + MinFree;
  660.     if (MemoryRequired > FreeMem) and not (SaveProjections) then begin
  661.             str := 'Insufficient memory to create entire stack of projections.  Projection images will be saved to disk.';
  662.             if (PutMessageWithCancel(str) = cancel) then
  663.                 Abort;
  664.             SaveProjections := TRUE;
  665.             SaveProjectionsTemp := TRUE;
  666.         end;
  667.     if (SaveProjections) then begin           {prepare to save projections as created if desired}
  668.             SaveAsWhat := AsTiff;
  669.             SaveAllState := SaveAllStage1;
  670.         end;
  671.     TimeStr := '?';
  672.     theta := InitAngle;                                     {begin rotation with user-specified angle}
  673.     ticksinit := TickCount;
  674.     for n := 1 to nProjections do begin
  675.             if (SaveProjections) or (n = 1) then begin    {open new window or stack slice}
  676.                     if SaveProjections then
  677.                         case AxisOfRotation of
  678.                             XAxis: 
  679.                                 str := StringOf('Projection X', theta : 4);
  680.                             YAxis: 
  681.                                 str := StringOf('Projection Y', theta : 4);
  682.                             ZAxis: 
  683.                                 str := StringOf('Projection Z', theta : 4);
  684.                         end
  685.                     else
  686.                         str := 'Projections';
  687.                     if not NewPicWindow(str, projwidth, projheight) then
  688.                         Abort;
  689.                 end
  690.             else if not (AddSlice(false)) then
  691.                 Abort;
  692.             str := StringOf('Projecting: ', n : 1, '/', nProjections : 1, ' (', Theta : 1, '°', ', ', TimeStr, ')');
  693.             ShowMeter;
  694.             UpdateMeter(0, str);
  695.             thetarad := theta * pi / 180;
  696.             costheta := round(bigpowerof2 * cos(thetarad));
  697.             sintheta := round(bigpowerof2 * sin(thetarad));
  698.             p := projptr;                                          {initialize required projection buffers}
  699.             InitializeBuffer(p, projsize, 255, 1);
  700.             if (ProjectionMethod = NearestPoint) or (Opacity > 0) then begin
  701.                     zp := zbufptr;
  702.                     InitializeBuffer(Ptr(zp), projsize, 32767, 2);
  703.                 end;     {then}
  704.             if (Opacity > 0) and (ProjectionMethod <> NearestPoint) then begin
  705.                     op := opaptr;
  706.                     InitializeBuffer(op, projsize, 255, 1);
  707.                 end;     {then}
  708.             if (ProjectionMethod = MeanValue) then begin
  709.                     sp := sumbufptr;
  710.                     cp := countbufptr;
  711.                     InitializeBuffer(Ptr(sp), projsize, 0, 4);
  712.                     InitializeBuffer(Ptr(cp), projsize, 0, 2);
  713.                 end;
  714.             if (ProjectionMethod = BrightestPoint) and (DepthCueInt < 100) then begin
  715.                     bp := brightcueptr;
  716.                     InitializeBuffer(bp, projsize, 255, 1);
  717.                     qp := cuezbufptr;
  718.                     InitializeBuffer(Ptr(qp), projsize, 255, 2);
  719.                 end;     {then}
  720.             UpdateMeter(10, str);
  721.             DestInfo := Info;
  722.             Info := SourceInfo;
  723.             case AxisOfRotation of
  724.                 XAxis: 
  725.                     DoOneProjectionX(nSlices, ycenter, zcenter, projwidth, projheight, costheta, sintheta, projptr, opaptr, brightcueptr, zbufptr, cuezbufptr, countbufptr, sumbufptr, str);
  726.                 YAxis: 
  727.                     DoOneProjectionY(nSlices, xcenter, zcenter, projwidth, projheight, costheta, sintheta, projptr, opaptr, brightcueptr, zbufptr, cuezbufptr, countbufptr, sumbufptr, str);
  728.                 ZAxis: 
  729.                     DoOneProjectionZ(nSlices, xcenter, ycenter, zcenter, projwidth, projheight, costheta, sintheta, projptr, opaptr, brightcueptr, zbufptr, cuezbufptr, countbufptr, sumbufptr, str);
  730.             end;
  731.             Info := DestInfo;
  732.             if n = 1 then
  733.                 TicksForOneProjection := TickCount - TicksInit;
  734.             TicksToGo := round((nProjections - n) * TicksForOneProjection);
  735.             seconds := StringOf((TicksToGo div 60) mod 60 : 2);
  736.             if seconds[1] = ' ' then
  737.                 seconds[1] := '0';
  738.             timestr := StringOf(TicksToGo div 3600 : 1, ':', seconds);
  739.             if (ProjectionMethod = MeanValue) then begin
  740.                     p := projptr;                                    {calculate the mean-value image from returned info}
  741.                     sp := sumbufptr;
  742.                     cp := countbufptr;
  743.                     for offset := 0 to projsize - 1 do begin
  744.                             if (cp^ > 0) then
  745.                                 p^ := sp^ div cp^;
  746.                             p := ptr(ord4(p) + 1);
  747.                             sp := LongPtr(ord4(sp) + 4);
  748.                             cp := IntPtr(ord4(cp) + 2);
  749.                         end;     {for}
  750.                 end;     {then}
  751.             if (Opacity > 0) and (ProjectionMethod <> NearestPoint) then begin
  752.                     p := projptr;                                    {calculate surface proj component (opacity on)}
  753.                     op := opaptr;                                     {and combine with another proj component}
  754.                     for offset := 0 to projsize - 1 do begin
  755.                             p^ := (Opacity * BAND(op^, 255) + (100 - Opacity) * BAND(p^, 255)) div 100;
  756.                             p := ptr(ord4(p) + 1);
  757.                             op := ptr(ord4(op) + 1);
  758.                         end;     {for}
  759.                 end;     {then}
  760.             if (AxisOfRotation = ZAxis) then begin  {interpolate for z-axis rotation}
  761.                     p := ptr(ord4(projptr) + projwidth);
  762.                     for offset := projwidth to projsize - 1 - projwidth do begin
  763.                             curval := BAND(p^, 255);
  764.                             prevval := BAND(ptr(ord4(p) - 1)^, 255);
  765.                             nextval := BAND(ptr(ord4(p) + 1)^, 255);
  766.                             aboveval := BAND(ptr(ord4(p) - projwidth)^, 255);
  767.                             belowval := BAND(ptr(ord4(p) + projwidth)^, 255);
  768.                             if (curval = 255) and (prevval <> 255) and (nextval <> 255) and (aboveval <> 255) and (belowval <> 255) then
  769.                                 p^ := (prevval + nextval + aboveval + belowval) div 4;
  770.                             p := ptr(ord4(p) + 1);
  771.                         end;
  772.                 end;
  773.             if (SaveProjections) or (n = 1) then
  774.                 BlockMove(projptr, Info^.PicBaseAddr, projsize)         {whole ROI write to projection image}
  775.             else
  776.                 BlockMove(projptr, Info^.StackInfo^.PicBaseH[n]^, projsize);
  777.             UpdateMeter(-1, '');        {dispose of meter}
  778.             if cancelled then begin
  779.                     if n > 1 then
  780.                         DeleteSlice;
  781.                     leave;
  782.                 end;
  783.             if (SaveProjections) then begin
  784.                     SaveAs('', 0);                                    {just save and put away current image after creating it}
  785.                     ignore := CloseAWindow(info^.wptr);
  786.                 end
  787.             else if n = 1 then begin  {create new stack for first projection if not saving projections}
  788.                     if not MakeStackFromWindow then
  789.                         Abort
  790.                 end;
  791.             theta := (theta + AngleInc) mod 360;
  792.             UpdatePicWindow;
  793.         end;     {for}
  794.     SaveAllState := NoSaveAll;
  795.     if SaveProjectionsTemp then                 {turn this back off if we turned it on due to lack of memory}
  796.         SaveProjections := FALSE;
  797.     DisposeProjectionPtrs(projptr, opaptr, brightcueptr, zbufptr, countbufptr, cuezbufptr, sumbufptr);
  798.     SetPort(tPort);
  799.     DestInfo := info;
  800.     info := SourceInfo;
  801.     SelectSlice(info^.StackInfo^.CurrentSlice);
  802.     if AutoSelectAll then
  803.         KillRoi;
  804.     info := DestInfo;
  805. end;     {procedure DoProjection}
  806.  
  807.  
  808. {******************************************************************************}
  809. {*     This procedure allows the user to set parameters for projection in a large dialog box.                                  *}
  810. {******************************************************************************}
  811. function ShowProjectDialogBox: boolean;
  812.     const
  813.         ProjectOptionsID = 128;
  814.         SliceIntervalID = 3;
  815.         InitAngleID = 4;
  816.         TotalAngleID = 5;
  817.         AngleIncID = 6;
  818.         TransparencyLowerID = 7;
  819.         TransparencyUpperID = 8;
  820.         OpacityID = 9;
  821.         DepthCueSurfID = 10;
  822.         DepthCueIntID = 11;
  823.         RotationAboutXID = 12;
  824.         RotationAboutYID = 13;
  825.         RotationAboutZID = 14;
  826.         SaveProjectionsID = 15;
  827.         MinProjSizeID = 16;
  828.         NearestID = 28;
  829.         BrightestID = 29;
  830.         MeanID = 30;
  831.     var
  832.         mylog: Dialogptr;                                           {pointer to dialog box}
  833.         i, item, alldone: integer;
  834.         SaveInitAngle, SaveTotalAngle, SaveAngleInc: integer;
  835.         SaveOpacity: integer;
  836.         SaveAxisOfRotation: AxisType;
  837.         SaveSaveProjections, SaveCloseSlices, SaveMinProjSize: Boolean;
  838.         PercentSurf, PercentInt: integer;
  839. begin
  840.     InitCursor;
  841.     SliceInterval := info^.StackInfo^.SliceSpacing;
  842.     if SliceInterval <= 0.0 then
  843.         SliceInterval := 1.0;
  844.     SaveInitAngle := InitAngle;
  845.     SaveTotalAngle := TotalAngle;
  846.     SaveAngleInc := AngleInc;
  847.     SaveOpacity := Opacity;
  848.     SaveAxisOfRotation := AxisOfRotation;
  849.     SaveSaveProjections := SaveProjections;
  850.     SaveMinProjSize := MinProjSize;
  851.     PercentSurf := 100 - DepthCueSurf;
  852.     PercentInt := 100 - DepthCueInt;
  853.     if DensitySlicing then
  854.         with info^ do begin
  855.                 lower := SliceStart;
  856.                 upper := SliceEnd;
  857.             end
  858.     else begin
  859.             lower := TransparencyLower;
  860.             upper := TransparencyUpper;
  861.         end;
  862.     mylog := GetNewDialog(ProjectOptionsID, nil, pointer(-1));
  863.     SetDReal(MyLog, SliceIntervalID, SliceInterval, 1);
  864.     SelIText(MyLog, SliceIntervalID, 0, 32767);
  865.     SetDNum(MyLog, InitAngleID, InitAngle);
  866.     SetDNum(MyLog, TotalAngleID, TotalAngle);
  867.     SetDNum(MyLog, AngleIncID, AngleInc);
  868.     SetDNum(MyLog, TransparencyLowerID, lower);
  869.     SetDNum(MyLog, TransparencyUpperID, upper);
  870.     SetDNum(MyLog, OpacityID, Opacity);
  871.     SetDNum(MyLog, DepthCueSurfID, PercentSurf);
  872.     SetDNum(MyLog, DepthCueIntID, PercentInt);
  873.     OutlineButton(MyLog, ok, 16);
  874.     SetDialogItem(MyLog, RotationAboutXID, ord(AxisOfRotation = XAxis));
  875.     SetDialogItem(MyLog, RotationAboutYID, ord(AxisOfRotation = YAxis));
  876.     SetDialogItem(MyLog, RotationAboutZID, ord(AxisOfRotation = ZAxis));
  877.     SetDialogItem(MyLog, NearestID, ord(ProjectionMethod = NearestPoint));
  878.     SetDialogItem(MyLog, BrightestID, ord(ProjectionMethod = BrightestPoint));
  879.     SetDialogItem(MyLog, MeanID, ord(ProjectionMethod = MeanValue));
  880.     SetDialogItem(MyLog, SaveProjectionsID, ord(SaveProjections));
  881.     SetDialogItem(MyLog, MinProjSizeID, ord(MinProjSize));
  882.     alldone := 0;
  883.     repeat  {if we don't do it this way, ModalDialog throws us into code checking after each keystroke}
  884.         repeat   {meaning you can't type in a 2 digit number}
  885.             ModalDialog(nil, item);
  886.             if item = SaveProjectionsID then begin
  887.                     SaveProjections := not SaveProjections;
  888.                     SetDialogItem(MyLog, SaveProjectionsID, ord(SaveProjections));
  889.                 end;
  890.             if item = MinProjSizeID then begin
  891.                     MinProjSize := not MinProjSize;
  892.                     SetDialogItem(MyLog, MinProjSizeID, ord(MinProjSize));
  893.                 end;
  894.             if (item = RotationAboutXID) or (item = RotationAboutYID) or (item = RotationAboutZID) then begin
  895.                     case item of
  896.                         RotationAboutXID: 
  897.                             AxisOfRotation := XAxis;
  898.                         RotationAboutYID: 
  899.                             AxisOfRotation := YAxis;
  900.                         RotationAboutZID: 
  901.                             AxisOfRotation := ZAxis;
  902.                     end;     {case}
  903.                     SetDialogItem(MyLog, RotationAboutXID, ord(AxisOfRotation = XAxis));
  904.                     SetDialogItem(MyLog, RotationAboutYID, ord(AxisOfRotation = YAxis));
  905.                     SetDialogItem(MyLog, RotationAboutZID, ord(AxisOfRotation = ZAxis));
  906.                 end;
  907.             if (item >= nearestID) and (item <= MeanID) then begin
  908.                     case item of
  909.                         NearestID: 
  910.                             ProjectionMethod := NearestPoint;
  911.                         BrightestID: 
  912.                             ProjectionMethod := BrightestPoint;
  913.                         MeanID: 
  914.                             ProjectionMethod := MeanValue;
  915.                     end;
  916.                     SetDialogItem(MyLog, NearestID, ord(projectionMethod = NearestPoint));
  917.                     SetDialogItem(MyLog, BrightestID, ord(projectionMethod = BrightestPoint));
  918.                     SetDialogItem(MyLog, MeanID, ord(projectionMethod = MeanValue));
  919.                 end;
  920.         until (item = ok) or (item = cancel);
  921.         alldone := 1;
  922.         if (item = ok) then begin  {check all the values that could have been entered, don't know which were changed}
  923.                 SliceInterval := GetDReal(MyLog, SliceIntervalID);
  924.                 if (SliceInterval <= 0.0) or (SliceInterval > 1023.0) then begin
  925.                         SliceInterval := info^.StackInfo^.SliceSpacing;
  926.                         SetDReal(MyLog, SliceIntervalID, SliceInterval, 1);
  927.                         beep;
  928.                         alldone := 0;
  929.                     end;  {if SliceInterval}
  930.                 InitAngle := GetDNum(MyLog, InitAngleID);
  931.                 if (InitAngle < 0) or (InitAngle > 360) then begin
  932.                         InitAngle := SaveInitAngle;
  933.                         SetDNum(MyLog, InitAngleID, InitAngle);
  934.                         beep;
  935.                         alldone := 0;
  936.                     end;  {if InitAngle}
  937.                 TotalAngle := GetDNum(MyLog, TotalAngleID);
  938.                 if (TotalAngle < 0) or (TotalAngle > 360) then begin
  939.                         TotalAngle := SaveTotalAngle;
  940.                         SetDNum(MyLog, TotalAngleID, TotalAngle);
  941.                         beep;
  942.                         alldone := 0;
  943.                     end;  {if TotalAngle}
  944.                 AngleInc := GetDNum(MyLog, AngleIncID);
  945.                 if (AngleInc < 0) or (AngleInc > 360) then begin
  946.                         AngleInc := SaveAngleInc;
  947.                         SetDNum(MyLog, AngleIncID, AngleInc);
  948.                         beep;
  949.                         alldone := 0;
  950.                     end;  {if AngleInc}
  951.                 lower := GetDNum(MyLog, TransparencyLowerID);
  952.                 if (lower < 0) or (lower > 255) then begin
  953.                         lower := TransparencyLower;
  954.                         SetDNum(MyLog, TransparencyLowerID, lower);
  955.                         beep;
  956.                         alldone := 0;
  957.                     end;  {if TransparencyLower}
  958.                 upper := GetDNum(MyLog, TransparencyUpperID);
  959.                 if (upper < 0) or (upper > 255) then begin
  960.                         upper := TransparencyUpper;
  961.                         SetDNum(MyLog, TransparencyUpperID, upper);
  962.                         beep;
  963.                         alldone := 0;
  964.                     end;  {if TransparencyUpper}
  965.                 Opacity := GetDNum(MyLog, OpacityID);
  966.                 if (Opacity < 0) or (Opacity > 100) then begin
  967.                         Opacity := SaveOpacity;
  968.                         SetDNum(MyLog, OpacityID, Opacity);
  969.                         beep;
  970.                         alldone := 0;
  971.                     end;  {if Opacity}
  972.                 PercentSurf := GetDNum(MyLog, DepthCueSurfID);
  973.                 if (PercentSurf < 0) or (PercentSurf > 100) then begin
  974.                         PercentSurf := 100 - DepthCueSurf;
  975.                         SetDNum(MyLog, DepthCueSurfID, PercentSurf);
  976.                         beep;
  977.                         alldone := 0;
  978.                     end;  {if DepthCueSurf}
  979.                 PercentInt := GetDNum(MyLog, DepthCueIntID);
  980.                 if (PercentInt < 0) or (PercentInt > 100) then begin
  981.                         PercentInt := 100 - DepthCueInt;
  982.                         SetDNum(MyLog, DepthCueIntID, PercentInt);
  983.                         beep;
  984.                         alldone := 0;
  985.                     end;  {if DepthCueInt}
  986.                 info^.StackInfo^.SliceSpacing := SliceInterval;
  987.             end;
  988.     until (alldone = 1);
  989.     DisposDialog(mylog);
  990.     if item = cancel then begin                       {if Cancel, keep the saved values}
  991.             InitAngle := SaveInitAngle;
  992.             TotalAngle := SaveTotalAngle;
  993.             AngleInc := SaveAngleInc;
  994.             Opacity := SaveOpacity;
  995.             AxisOfRotation := SaveAxisOfRotation;
  996.             SaveProjections := SaveSaveProjections;
  997.             MinProjSize := SaveMinProjSize;
  998.             ShowProjectDialogBox := false;
  999.         end
  1000.     else begin
  1001.             if not DensitySlicing then begin
  1002.                     TransparencyLower := lower;
  1003.                     TransparencyUpper := upper;
  1004.                 end;
  1005.             DepthCueSurf := 100 - PercentSurf;
  1006.             DepthCueInt := 100 - PercentInt;
  1007.             ShowProjectDialogBox := true;
  1008.         end;
  1009. end;
  1010.  
  1011.  
  1012. procedure Project;
  1013. begin
  1014.     if ShowProjectDialogBox then
  1015.         DoProjection;
  1016. end;
  1017.  
  1018.  
  1019. end.